/*

Miranda IM: the free IM client for Microsoft* Windows*

Copyright 2000-2007 Miranda ICQ/IM project, 
all portions of this codebase are copyrighted to the people 
listed in contributors.txt.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or ( at your option ) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
aLONG with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#include "commonheaders.h"
#include "ExtraServices.h"
#include "m_protocols.h"
#include "m_png.h"
#include "m_avatars.h"

namespace NServices 
{
	namespace NAvatar 
	{

		static HANDLE ghChangedHook = NULL;

/*
		int SaveBitmapAsAvatar( HBITMAP hBitmap, LPCSTR szFileName ) 
		{
			BITMAPINFO* bmi;
			HDC hdc;
			HBITMAP hOldBitmap;
			BITMAPINFOHEADER* pDib;
			BYTE* pDibBits;
			long dwPngSize = 0;
			DIB2PNG convertor;
			FILE* out;

			// file exists?
			out = fopen( szFileName, "rb" );
			if( out != NULL ) {
				fclose( out );
				return ERROR_SUCCESS;
			}	

			if( !ServiceExists( MS_DIB2PNG ) ) {
				MsgErr( NULL, TranslateT( "Your png2dib.dll is either obsolete or damaged.") );
				return 1;
			}

			hdc = CreateCompatibleDC( NULL );
			hOldBitmap = ( HBITMAP )SelectObject( hdc, hBitmap );

			bmi = ( BITMAPINFO* )_alloca( sizeof( BITMAPINFO ) + sizeof( RGBQUAD ) * 256 );
			memset( bmi, 0, sizeof( BITMAPINFO ) );
			bmi->bmiHeader.biSize = 0x28;
			if( GetDIBits( hdc, hBitmap, 0, 96, NULL, bmi, DIB_RGB_COLORS ) == 0 ) {
				return 2;
			}

			pDib = ( BITMAPINFOHEADER* )GlobalAlloc( LPTR, sizeof( BITMAPINFO ) + sizeof( RGBQUAD ) * 256 + bmi->bmiHeader.biSizeImage );
			if( pDib == NULL )
				return 3;

			memcpy( pDib, bmi, sizeof( BITMAPINFO ) + sizeof( RGBQUAD ) * 256 );
			pDibBits = ( ( BYTE* )pDib ) + sizeof( BITMAPINFO ) + sizeof( RGBQUAD ) * 256;

			GetDIBits( hdc, hBitmap, 0, pDib->biHeight, pDibBits, ( BITMAPINFO* )pDib, DIB_RGB_COLORS );
			SelectObject( hdc, hOldBitmap );
			DeleteDC( hdc );

			convertor.pbmi = ( BITMAPINFO* )pDib;
			convertor.pDiData = pDibBits;
			convertor.pResult = NULL;
			convertor.pResultLen = &dwPngSize;
			if( !CallService( MS_DIB2PNG, 0, ( LPARAM )&convertor ) ) {
				GlobalFree( pDib );
				return 2;
			}

			convertor.pResult = ( PBYTE )mir_alloc( dwPngSize );
			CallService( MS_DIB2PNG, 0, ( LPARAM )&convertor );

			GlobalFree( pDib );
				
			out = fopen( szFileName, "wb" );
			if( out != NULL ) {
				fwrite( convertor.pResult, dwPngSize, 1, out );
				fclose( out );
			}	

			mir_free( convertor.pResult );

			return ERROR_SUCCESS;
		}
*/

		static INT GetContactAvatarFileName( LPCTSTR zodiac, LPSTR szFileName, INT cchFileName )
		{
			if( !CallService( MS_DB_GETPROFILEPATH, ( WPARAM )cchFileName, ( LPARAM )szFileName ) ) 
			{
				int len = mir_strlen( szFileName );
		#ifdef _UNICODE
				CHAR tmp[64];

				if( WideCharToMultiByte( CP_ACP, 0, zodiac, 64, tmp, SIZEOF( tmp ),0,0 ) > 0 ) 
				{
					mir_snprintfA( szFileName + len, cchFileName - len, "\\avatars\\%s.png", tmp );
				}
		#else
				mir_snprintfA( szFileName + len, cchFileName - len, "\\avatars\\%s.png", zodiac );
		#endif
				return !PathFileExistsA( szFileName );
			}
			return 1;
		}

		/**
		 *
		 *
		 **/
		static VOID SetZodiacAvatar( HANDLE hContact ) 
		{
			MAnnivDate mtb;

			// try to load birthday for contact
			if( !mtb.DBGetBirthDate( hContact ) )
			{
				MZodiac zodiac;
				//ICONINFO iinfo;
				CHAR szFileName[MAX_PATH];
				
				// get zodiac for birthday
				zodiac = mtb.Zodiac();

				if( !GetContactAvatarFileName( zodiac.pszName, szFileName, SIZEOF( szFileName ) ) ) 
				{
					// extract the bitmap from the icon
					//GetIconInfo( zodiac.hIcon, &iinfo );

					// save the bitmap to a file used as avatar later
					//if( !SaveBitmapAsAvatar( iinfo.hbmColor, szFileName ) ) 
					{
						if( !CallService( MS_AV_SETAVATAR, ( WPARAM )hContact, ( LPARAM )szFileName ) )
						{
							DB::Setting::WriteByte( hContact, "ContactPhoto", "IsZodiac", 1 );
						}
					}
				}
			}
		}

		VOID DeleteAvatar( HANDLE hContact )
		{
			if( hContact && DB::Setting::GetByte( hContact, "ContactPhoto", "IsZodiac", FALSE ) )
			{
				//AVATARCACHEENTRY *ace;
				LPSTR szProto = DB::Contact::Proto( hContact );

				DB::Setting::Delete( hContact, "ContactPhoto", "File" );
				DB::Setting::Delete( hContact, "ContactPhoto", "RFile" );
				DB::Setting::Delete( hContact, "ContactPhoto", "Backup" );
				DB::Setting::Delete( hContact, "ContactPhoto", "ImageHash" );

				DB::Setting::WriteByte( hContact, "ContactPhoto", "IsZodiac", 0 );
				
				/*
				ace = ( AVATARCACHEENTRY * )CallService( MS_AV_GETMYAVATAR, NULL, ( LPARAM )szProto );
				if( ace )
				{
					if( !CallService( MS_AV_SETAVATAR, ( WPARAM )hContact, ( LPARAM )ace->szFilename ) )
					{
						DB::Setting::WriteByte( hContact, "ContactPhoto", "IsZodiac", 0 );
					}
				}
				*/
			}
		}


		/**
		 *
		 *
		 **/
		static INT OnAvatarChanged( HANDLE hContact, AVATARCACHEENTRY *ace )
		{
			if( hContact )
			{
				// check valid parameters
				if( ace )
				{
					if( // check for correct structure
							ace->cbSize == sizeof( AVATARCACHEENTRY ) && 
							// set zodiac as avatar either if the desired avatar is invalid or a general protocol picture
						  ( ( ace->dwFlags & AVS_PROTOPIC ) || !( ace->dwFlags & AVS_BITMAP_VALID ) ) )
					{
						if( !DB::Setting::GetByte( hContact, "ContactPhoto", "IsZodiac", 0 ) )
						{
							SetZodiacAvatar( hContact );
						}
					}
					else
					{
						DB::Setting::WriteByte( hContact, "ContactPhoto", "IsZodiac", 0 );
					}
				}

				// avatar was deleted, so we can set up a zodiac avatar
				else
				{
					SetZodiacAvatar( hContact );
				}
			}
			return 0;
		}

		/**
		 *
		 *
		 **/
		VOID Enable( BOOLEAN bEnable ) 
		{
			HANDLE hContact;
			DBVARIANT dbv;

			if( bEnable && !ghChangedHook ) 
			{

				//walk through all the contacts stored in the DB
				for( hContact = DB::Contact::FindFirst();
					hContact != NULL;
					hContact = DB::Contact::FindNext( hContact ) )
				{
					// don't set if avatar is locked!
					if( !DB::Setting::GetByte( hContact, "ContactPhoto", "Locked", 0 ) ) 
					{
						BOOLEAN bInvalidAvatar = TRUE;
						
						// the relative file is valid
						if( !DB::Setting::GetAString( hContact, "ContactPhoto", "RFile", &dbv ) ) 
						{
							CHAR absolute[MAX_PATH];

							// check if file exists
							if( !CallService( MS_UTILS_PATHTOABSOLUTE, ( WPARAM )dbv.pszVal, ( LPARAM )absolute ) ) 
							{
								FILE *f = fopen( absolute, "rb" );
								if( f ) {
									bInvalidAvatar = FALSE;
									fclose( f );
								}
							}
							DB::Variant::Free( &dbv );
						}

						// the absolute file is valid
						if( bInvalidAvatar && !DBGetContactSetting( hContact, "ContactPhoto", "File", &dbv ) ) 
						{
							FILE *f = fopen( dbv.pszVal, "rb" );
							if( f ) {
								bInvalidAvatar = FALSE;
								fclose( f );
							}
							DB::Variant::Free( &dbv );
						}
						
						// set the zodiac as avatar
						if( bInvalidAvatar ) {
							SetZodiacAvatar( hContact );
						}
					}
				}
				ghChangedHook = HookEvent( ME_AV_AVATARCHANGED, ( MIRANDAHOOK ) OnAvatarChanged );
			}
			else if( !bEnable && ghChangedHook ) 
			{
				UnhookEvent( ghChangedHook );
				ghChangedHook = NULL;

				//walk through all the contacts stored in the DB
				for( hContact = DB::Contact::FindFirst();
						 hContact != NULL;
						 hContact = DB::Contact::FindNext( hContact ) )
				{
					DeleteAvatar( hContact );
				}
			}
		}


		/**
		 * name:	OnModulesLoaded
		 * desc:	initialize stuff, which require all standard modules to bee loaded
		 * params:	none
		 * return:	0
		 **/
		VOID OnModulesLoaded()
		{
			Enable( DB::Setting::GetByte( SET_ZODIAC_AVATARS, FALSE ) );
		}

	} /* namespace NAvatar */
} /* namespace NServices */